import os
import subprocess
from moviepy.editor import VideoFileClip
import whisper
import time
import hashlib
import json
import logging
import threading
import queue  # pylint: disable=unused-import
from config import TRANSCRIPTION_CACHE_DIR

logger = logging.getLogger(__name__)

class VideoProcessor:
    def _format_timestamp(self, seconds):
        """将秒数转换为时间戳格式"""
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        seconds = int(seconds % 60)
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"

    def __init__(self):
        logger.info("正在初始化Whisper模型...")
        self.model = whisper.load_model("base")
        logger.info("Whisper模型加载完成")
        self._check_ffmpeg()
        self.cache_dir = TRANSCRIPTION_CACHE_DIR
        self._ensure_cache_dir()
        self.progress_queue = queue.Queue()
        self.progress_thread = None
        self.stop_progress = False
        
    def _check_ffmpeg(self):
        """检查ffmpeg是否已安装"""
        try:
            subprocess.run(['ffmpeg', '-version'], capture_output=True, check=True, encoding='utf-8')
            logger.info("FFmpeg检查通过")
        except FileNotFoundError:
            error_msg = "未找到ffmpeg。请安装ffmpeg并确保它在系统PATH中。\n" \
                       "Windows安装方法：\n" \
                       "1. 使用chocolatey: choco install ffmpeg\n" \
                       "2. 或手动下载：https://github.com/BtbN/FFmpeg-Builds/releases"
            logger.error(error_msg)
            raise Exception(error_msg)
        
    def _ensure_cache_dir(self):
        """确保缓存目录存在"""
        if not os.path.exists(self.cache_dir):
            os.makedirs(self.cache_dir)
            logger.info(f"创建缓存目录: {self.cache_dir}")
            
    def _get_video_hash(self, video_path):
        """计算视频文件的哈希值"""
        if not os.path.isfile(video_path):
            raise ValueError(f"无效的视频文件路径: {video_path}")
            
        sha256_hash = hashlib.sha256()
        with open(video_path, "rb") as f:
            for byte_block in iter(lambda: f.read(4096), b""):
                sha256_hash.update(byte_block)
        return sha256_hash.hexdigest()
        
    def _get_cache_path(self, video_path):
        """获取缓存文件路径"""
        if not os.path.isfile(video_path):
            raise ValueError(f"无效的视频文件路径: {video_path}")
            
        video_hash = self._get_video_hash(video_path)
        return os.path.join(self.cache_dir, f"{video_hash}.json")
        
    def _save_to_cache(self, video_path, text, subtitles=None):
        """保存转写文本和字幕到缓存"""
        try:
            if not os.path.isfile(video_path):
                raise ValueError(f"无效的视频文件路径: {video_path}")
                
            cache_path = self._get_cache_path(video_path)
            logger.debug(f"保存缓存 - 视频路径: {video_path}")
            logger.debug(f"保存缓存 - 缓存路径: {cache_path}")
            logger.debug(f"缓存目录是否存在: {os.path.exists(self.cache_dir)}")
            logger.debug(f"缓存目录权限: {oct(os.stat(self.cache_dir).st_mode)[-3:]}")
            
            # 确保缓存目录存在
            os.makedirs(self.cache_dir, exist_ok=True)
            logger.debug("缓存目录已创建/确认")
            
            # 保存原始转写文本和段落
            cache_data = {
                "video_path": video_path,
                "raw_text": text,  # 保存原始转写文本
                "paragraphs": text.split('\n\n'),  # 保存段落列表
                "timestamp": os.path.getmtime(video_path)
            }
            
            # 尝试写入文件
            logger.debug("正在写入缓存文件...")
            with open(cache_path, "w", encoding="utf-8") as f:
                json.dump(cache_data, f, ensure_ascii=False, indent=2)
            logger.info("缓存保存成功")
        except Exception as e:
            logger.error(f"保存缓存时出错: {str(e)}", exc_info=True)
            raise
            
    def _load_from_cache(self, video_path):
        """从缓存加载转写文本"""
        if not os.path.isfile(video_path):
            logger.debug(f"无效的视频文件路径: {video_path}")
            return None
            
        cache_path = self._get_cache_path(video_path)
        if not os.path.exists(cache_path):
            logger.debug(f"缓存文件不存在: {cache_path}")
            return None
            
        try:
            with open(cache_path, "r", encoding="utf-8") as f:
                cache_data = json.load(f)
                # 检查视频文件是否被修改
                if cache_data["timestamp"] == os.path.getmtime(video_path):
                    logger.info("从缓存加载转写文本")
                    # 返回原始转写文本
                    return cache_data["raw_text"]
                else:
                    logger.debug("视频文件已修改，缓存无效")
        except Exception as e:
            logger.error(f"读取缓存时出错: {str(e)}", exc_info=True)
        return None

    def extract_audio(self, video_path):
        """从视频中提取音频"""
        try:
            # 在缓存目录创建临时文件来存储音频
            audio_path = os.path.join(self.cache_dir, f"temp_audio_{int(time.time())}.mp3")
            logger.debug(f"临时音频文件路径: {audio_path}")
            
            logger.info("正在加载视频...")
            video = VideoFileClip(video_path)
            logger.info(f"视频时长: {video.duration}秒")
            
            logger.info("正在提取音频...")
            # 使用ffmpeg直接提取音频，这样更快
            ffmpeg_cmd = [
                'ffmpeg', '-i', video_path,
                '-vn',  # 不处理视频
                '-acodec', 'libmp3lame',  # 使用mp3编码
                '-q:a', '2',  # 音频质量
                '-y',  # 覆盖已存在的文件
                audio_path
            ]
            
            logger.debug(f"执行FFmpeg命令: {' '.join(ffmpeg_cmd)}")
            # 使用encoding='utf-8'来处理输出
            process = subprocess.Popen(
                ffmpeg_cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                encoding='utf-8',
                errors='replace'  # 使用replace来处理无法解码的字符
            )
            
            # 等待处理完成
            stdout, stderr = process.communicate()
            
            if process.returncode != 0:
                error_msg = f"FFmpeg错误: {stderr}"
                logger.error(error_msg)
                raise Exception(error_msg)
            
            logger.info(f"音频文件大小: {os.path.getsize(audio_path) / 1024 / 1024:.2f} MB")
            logger.info("音频提取完成")
            return audio_path
            
        except Exception as e:
            logger.error(f"提取音频时出错: {str(e)}", exc_info=True)
            raise
        finally:
            if 'video' in locals():
                video.close()

    def _progress_worker(self, total_duration):
        """进度更新工作线程"""
        while not self.stop_progress:
            try:
                # 从队列获取进度更新，设置超时以便能够响应停止信号
                queue_data = self.progress_queue.get(timeout=1)
                if queue_data is None:  # 停止信号
                    break
                    
                # 提取时间值并计算进度
                end_time = queue_data[0] if isinstance(queue_data, tuple) else queue_data

                    
                # 计算并更新进度
                try:
                    progress = (end_time / total_duration) * 100
                except (TypeError, ValueError) as e:
                    logger.error(f"进度计算错误: {e}")
                    continue
                logger.debug(f"更新进度: {progress:.1f}%")
                # Put progress update in queue for main thread to handle
                self.progress_queue.put(('progress', progress))
                
            except queue.Empty:
                continue
            except Exception as e:
                logger.error(f"进度更新线程出错: {str(e)}", exc_info=True)
                break

    def transcribe_audio(self, audio_path, video_path=None, progress_callback=None, status_callback=None):
        """转写音频为文字"""
        processed_text = "未检测到语音内容"  # 默认值初始化
        try:
            logger.info("=== 开始音频转写过程 ===")
            logger.debug(f"音频文件路径: {audio_path}")
            logger.debug(f"音频文件是否存在: {os.path.exists(audio_path)}")
            logger.debug(f"音频文件大小: {os.path.getsize(audio_path) / 1024 / 1024:.2f} MB")
            
            # 检查是否有缓存
            if video_path:
                logger.debug(f"视频文件路径: {video_path}")
                logger.debug(f"视频文件是否存在: {os.path.exists(video_path)}")
                cached_text = self._load_from_cache(video_path)
                if cached_text:
                    logger.info("从缓存加载转写文本")
                    if progress_callback:
                        progress_callback(100)  # 从缓存加载时，进度为100%
                    if status_callback:
                        status_callback("从缓存加载转写文本")
                    processed_text = cached_text  # 确保变量已赋值
                    return processed_text
            
            if status_callback:
                status_callback("正在加载音频文件...")
            
            # 加载音频文件
            audio = whisper.load_audio(audio_path)
            
            if status_callback:
                status_callback("正在处理音频...")
            
            # 获取音频时长（秒）
            total_duration = len(audio) / whisper.audio.SAMPLE_RATE
            logger.info(f"音频总时长: {total_duration:.2f}秒")
            
            # 转写音频
            if status_callback:
                status_callback("正在转写音频为文字...")
            
            # 启动进度更新线程
            if progress_callback:
                self.stop_progress = False
                self.progress_thread = threading.Thread(
                    target=self._progress_worker,
                    args=(total_duration,)
                )
                self.progress_thread.start()
            
            # 使用whisper的transcribe方法
            result = self.model.transcribe(
                audio,
                language="zh",
                task="transcribe",
                fp16=False,
                verbose=True  # 启用详细输出
            )
            
            # 处理转写结果，生成带时间戳的字幕
            if "segments" in result:
                logger.debug(f"开始处理 {len(result['segments'])} 个转写片段")
                subtitles = []
                for segment in result["segments"]:
                    # 输出每个时间段的转写结果
                    start_time = segment["start"]
                    end_time = segment["end"]
                    text = segment["text"].strip()
                    
                    # 生成时间戳格式
                    start_timestamp = self._format_timestamp(start_time)
                    end_timestamp = self._format_timestamp(end_time)
                    
                    # 生成字幕行
                    # 记录时间戳信息（毫秒精度）
                    timestamp_data = {
                        "start": round(start_time * 1000),
                        "end": round(end_time * 1000),
                        "text": text
                    }
                    subtitles.append(timestamp_data)
                    
                    logger.info(f"[{start_time:.2f}s -> {end_time:.2f}s] {text}")
                    # 将时间戳信息传递给进度队列
                    self.progress_queue.put(('timestamp', timestamp_data))
                
                # 将字幕保存到缓存
                if audio_path:
                    try:
                        self._save_to_cache(audio_path, result["text"], subtitles)
                        logger.info("转写结果和字幕已保存到缓存")
                    except Exception as e:
                        logger.error(f"保存缓存时出错: {str(e)}", exc_info=True)
                    
                    # 将进度更新发送到队列
                    if progress_callback:
                        self.progress_queue.put(end_time)
            
            # 停止进度更新线程
            if progress_callback:
                self.stop_progress = True
                self.progress_queue.put(None)  # 发送停止信号
                if self.progress_thread:
                    self.progress_thread.join()
            
            if status_callback:
                status_callback("音频转写完成")
            
            # 保存到缓存
            if video_path:
                try:
                    self._save_to_cache(video_path, result["text"])
                    logger.info("转写结果已保存到缓存")
                except Exception as e:
                    logger.error(f"保存缓存时出错: {str(e)}", exc_info=True)
            
            # 确保处理后的文本始终有值
            try:
                processed_text = result.get("text", "")
                if not processed_text:
                    logger.warning("转写结果为空，可能是静音视频")
                    processed_text = "未检测到语音内容"
            except AttributeError as e:
                logger.error(f"转写结果格式异常: {str(e)}")
                processed_text = "语音转写结果解析失败"
            
            # 添加后处理步骤
            try:
                # 简单清理文本
                processed_text = processed_text.replace('\n', ' ').strip()
                logger.debug("文本后处理完成")
            except Exception as e:
                logger.error(f"文本后处理失败: {str(e)}")
                processed_text = "文本处理错误: " + str(e)
            
            # 确保processed_text在返回前已定义且非空
            if not processed_text or not isinstance(processed_text, str):
                logger.warning("转写结果无效，使用默认文本")
                processed_text = "未检测到语音内容"
            
            return processed_text
        except Exception as e:
            logger.error(f"转写音频时出错: {str(e)}", exc_info=True)
            if status_callback:
                status_callback(f"音频转写失败: {str(e)}")
            # 确保进度更新线程被停止
            if progress_callback:
                self.stop_progress = True
                self.progress_queue.put(None)
                if self.progress_thread:
                    self.progress_thread.join()
            # 最终保障初始化
            processed_text = "语音转写过程中发生未知错误"
            return processed_text
